package mz.behaveas.model.ducktype {

	/**
	 * A class that provides a posibility to check a subset of properties of an instance.
	 * 
	 * @author maxim.zaks@gmail.com
	 */
	public class Duck {
		
		private var report: String = "";
		private var input : *;
		
		/**
		 * Creating a duck type.
		 */
		public static function type(input : *) : Duck{
			return new Duck(input);
		}
		
		public function Duck(input : *) {
			this.input = input;
		}

		public function equals(value : Object) : Boolean {
			
			for (var memberName : String in input) {
				
				var inputMember : * = input[memberName];
				
				if(memberName=="_type_"){
					if(!(value is inputMember)){
						report += "Expected " + inputMember + " but _type_ was " + value + "." + "\n"; 
					}
					continue;
				}
				
				var member : *;
				try{ 
					member = value[memberName];
				}catch(e : Error){
					report += "Expected member '" + memberName + "' not found." + "\n";
					continue;
				}
				
				if(member is Function){
					member = member();
				}
				
				if(inputMember is Duck) {
					if(!Duck(inputMember).equals(member)){
						report += Duck(inputMember).getReport() + "\n";
					}
					continue;
				}
				
				if(inputMember is Array && member is Array){
					if(!arraysAreEqual(inputMember, member)){
						report += "Expected " + inputMember + " got " + member + " for key '" + memberName + "'." + "\n";
					}
					continue;
				}
				
				if(member != inputMember) {
					report += "Expected " + inputMember + " got " + member + " for key '" + memberName + "'." + "\n";
				}
			}
			
			return report.length==0;
		}
		
		public function getReport() : String {
			return report;
		}

	}
}
